﻿#include "GUIVisibilityDialog.h"
#include "ui_GUIVisibilityDialog.h"

#include "PickDataProvider/GUIPickInfo.h"
#include "PickDataProvider/PickedData.h"
#include "PickDataProvider/PickedDataProvider.h"
#include "OperatorsInterface/GraphEventOperator.h"
#include "OperatorsInterface/TreeEventOperator.h"

#include "FITK_Kernel/FITKCore/FITKOperatorRepo.h"
#include "FITK_Kernel/FITKCore/FITKDataRepo.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsDiscModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsSEAModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractSEASubSys.h"
#include "FITK_Component/FITKAcousticsModel/FITKSEAAbstractJunction.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsFEModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractFESubSys.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsFEFace.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsSensors.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsGeometryData.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsPhysics.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsLoadManager.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKAbsVirtualTopo.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKAbsVirtualTopoMapper.h"

#include <QButtonGroup>


namespace GUI
{
    GUIVisibilityDialog::GUIVisibilityDialog() :
        GUIDialogBase(FITKAPP->getGlobalData()->getMainWindow())
    {
        _ui = new Ui::GUIVisibilityDialog();
        _ui->setupUi(this);
        _pickWidget = new GUIPickWidget();
        _ui->verticalLayout->addWidget(_pickWidget);
        setWindowTitle(tr("Edit Visibility Dialog"));
    }

    GUIVisibilityDialog::~GUIVisibilityDialog()
    {
        if (_ui) {
            delete _ui;
            _ui = nullptr;
        }
        if (_pickWidget) {
            delete _pickWidget;
            _pickWidget = nullptr;
        }
    }

    void GUIVisibilityDialog::on_pushButton_Hide_clicked()
    {
        EventOper::GraphEventOperator* operGraph = FITKOPERREPO->getOperatorT<EventOper::GraphEventOperator>("GraphPreprocess");
        if (_pickWidget == nullptr && operGraph == nullptr)return;
        //获取拾取数据
        QList<int> idList = _pickWidget->getPickValue();
        if (idList.isEmpty()) return;
        //清空拾取
        _pickWidget->resetPickToNone();
        //设置检查几何关联关系
        _isCheckGeoConnect = true;
        //隐藏拾取项
        showOrHide(_pickWidget->getCurrentPickType(), false, idList);
        //重新设置拾取状态
        _pickWidget->resetPickToCurrentSelect();
    }

    void GUIVisibilityDialog::on_pushButton_ShowOnly_clicked()
    {
        EventOper::GraphEventOperator* operGraph = FITKOPERREPO->getOperatorT<EventOper::GraphEventOperator>("GraphPreprocess");
        if (_pickWidget == nullptr && operGraph == nullptr)return;
        //获取拾取数据
        QList<int> idList = _pickWidget->getPickValue();
        if (idList.isEmpty()) return;
        //清空拾取
        _pickWidget->resetPickToNone();
        //设置检查几何关联关系
        _isCheckGeoConnect = false;
        //隐藏所有
        showOrHide(_pickWidget->getCurrentPickType(), false);
        //显示拾取项
        showOrHide(_pickWidget->getCurrentPickType(), true, idList);
        //重新设置拾取状态
        _pickWidget->resetPickToCurrentSelect();
    }

    void GUIVisibilityDialog::on_pushButton_ShowAll_clicked()
    {
        if (_pickWidget == nullptr)return;
        //清空拾取
        _pickWidget->resetPickToNone();
        //设置检查几何关联关系
        _isCheckGeoConnect = false;
        //显示设置
        showOrHide(_pickWidget->getCurrentPickType(), true);
        //重新设置拾取状态
        _pickWidget->resetPickToCurrentSelect();
    }

    void GUIVisibilityDialog::on_pushButton_InvertSelection_clicked()
    {
        EventOper::GraphEventOperator* operGraph = FITKOPERREPO->getOperatorT<EventOper::GraphEventOperator>("GraphPreprocess");
        if (_pickWidget == nullptr && operGraph == nullptr)return;

        switch (_pickWidget->getCurrentPickType()) {
        case GUI::GUIDialogPickType::Geometry: {
            QList<Interface::FITKAbsVirtualTopo*> virTopoList = getAllGeometryVirTopos();
            for (Interface::FITKAbsVirtualTopo* virTopo : virTopoList) {
                if (virTopo == nullptr) {
                    continue;
                }
                virTopo->enable(!virTopo->isEnable());
            }
            //更新模型树界面item状态（该函数的调用需在刷新渲染之前）
            updateModelTreeWidgetItem();
            //刷新渲染层
            operGraph->updateGeometrys(true, true);
            break;
        }
        case GUI::GUIDialogPickType::SubSysteam: {
            //SEA子系统
            if (_SEAModel && _SEAModel->getSEASubSysManager()) {
                for (int i = 0; i < _SEAModel->getSEASubSysManager()->getDataCount(); i++) {
                    Acoustics::FITKAbstractSEASubSys* subSys = _SEAModel->getSEASubSysManager()->getDataByIndex(i);
                    if (subSys == nullptr)continue;
                    subSys->enable(!subSys->isEnable());
                }
            }
            //FE子系统
            if (_FEModel && _FEModel->getFESubSysManager()) {
                for (int i = 0; i < _FEModel->getFESubSysManager()->getDataCount(); i++) {
                    Acoustics::FITKAbstractFESubSys* subSys = _FEModel->getFESubSysManager()->getDataByIndex(i);
                    if (subSys == nullptr)continue;
                    subSys->enable(!subSys->isEnable());
                }
            }
            //FE面
            if (_FEModel && _FEModel->getFEFaceManager()) {
                for (int i = 0; i < _FEModel->getFEFaceManager()->getDataCount(); i++) {
                    Acoustics::FITKAcousticsFEFace* face = _FEModel->getFEFaceManager()->getDataByIndex(i);
                    if (face == nullptr)continue;
                    face->enable(!face->isEnable());
                }
            }
            //传感器
            if (_FEModel && _FEModel->getSensorManager()) {
                for (int i = 0; i < _FEModel->getSensorManager()->getDataCount(); i++) {
                    Acoustics::FITKAcousticsSensors* sensor = _FEModel->getSensorManager()->getDataByIndex(i);
                    if (sensor == nullptr)continue;
                    sensor->enable(!sensor->isEnable());
                }
            }
            //更新模型树界面item状态（该函数的调用需在刷新渲染之前）
            updateModelTreeWidgetItem();
            //刷新渲染层
            operGraph->updateSEASubSystems();
            operGraph->updateFESubSystems();
            operGraph->updateFEFaces();
            operGraph->updateSensors();
            break;
        }
        case GUI::GUIDialogPickType::Load: {
            if (_physics && _physics->getFITKAcousticsLoadManager()) {
                for (int i = 0; i < _physics->getFITKAcousticsLoadManager()->getDataCount(); i++) {
                    Acoustics::FITKAcousticsAbstractLoad* load = _physics->getFITKAcousticsLoadManager()->getDataByIndex(i);
                    if (load == nullptr)continue;
                    load->enable(!load->isEnable());
                }
            }
            //更新模型树界面item状态（该函数的调用需在刷新渲染之前）
            updateModelTreeWidgetItem();
            //刷新渲染层
            operGraph->updateLoads();
            break;
        }
        case GUI::GUIDialogPickType::Junction: {
            if (_DiscModel && _DiscModel->getJunctionManager()) {
                for (int i = 0; i < _DiscModel->getJunctionManager()->getDataCount(); i++) {
                    Acoustics::FITKAbstractJunction* junction = _DiscModel->getJunctionManager()->getDataByIndex(i);
                    if (junction == nullptr)continue;
                    junction->enable(!junction->isEnable());
                }
            }
            //更新模型树界面item状态（该函数的调用需在刷新渲染之前）
            updateModelTreeWidgetItem();
            //刷新渲染层
            operGraph->updateJunctions();
            break;
        }
        }
        _pickWidget->resetPickToCurrentSelect();
    }

    void GUIVisibilityDialog::on_pushButton_Close_clicked()
    {
        this->close();
    }

    void GUIVisibilityDialog::showOrHide(GUIDialogPickType type, bool isShow, QList<int> idList)
    {
        EventOper::GraphEventOperator* operGraph = FITKOPERREPO->getOperatorT<EventOper::GraphEventOperator>("GraphPreprocess");
        if (_pickWidget == nullptr && operGraph == nullptr)return;

        switch (type) {
        case GUI::GUIDialogPickType::Geometry: {
            if (idList.isEmpty()) {
                QList<Interface::FITKAbsVirtualTopo*> virTopoList = getAllGeometryVirTopos();
                for (Interface::FITKAbsVirtualTopo* virTopo : virTopoList) {
                    if (virTopo == nullptr) {
                        continue;
                    }
                    virTopo->enable(isShow);
                }
            }
            else {
                for (int id : idList) {
                    Interface::FITKAbsVirtualTopo* virTopo = FITKDATAREPO->getTDataByID<Interface::FITKAbsVirtualTopo>(id);
                    if (virTopo == nullptr) {
                        continue;
                    }
                    virTopo->enable(isShow);
                }
            }

            if (_isCheckGeoConnect == true) {
                //检查几何线是否显示
                checkGeoEdgeIsShow();
                //检查几何点是否显示
                checkGeoPointIsShow();
            }
            //更新模型树界面item状态（该函数的调用需在刷新渲染之前）
            updateModelTreeWidgetItem();
            //刷新渲染层
            operGraph->updateGeometrys(true, true);
            break;
        }
        case GUI::GUIDialogPickType::SubSysteam: {
            //判断SEA子系统
            if (_SEAModel && _SEAModel->getSEASubSysManager()) {
                if (idList.isEmpty()) {
                    for (int i = 0; i < _SEAModel->getSEASubSysManager()->getDataCount(); i++) {
                        Acoustics::FITKAbstractSEASubSys* subSys = _SEAModel->getSEASubSysManager()->getDataByIndex(i);
                        if (subSys == nullptr)continue;
                        subSys->enable(isShow);
                    }
                }
                else {
                    for (int i : idList) {
                        Acoustics::FITKAbstractSEASubSys* subSys = _SEAModel->getSEASubSysManager()->getDataByID(i);
                        if (subSys == nullptr)continue;
                        subSys->enable(isShow);
                    }
                }
            }
            //判断FE子系统
            if (_FEModel && _FEModel->getFESubSysManager()) {
                if (idList.isEmpty()) {
                    for (int i = 0; i < _FEModel->getFESubSysManager()->getDataCount(); i++) {
                        Acoustics::FITKAbstractFESubSys* subSys = _FEModel->getFESubSysManager()->getDataByIndex(i);
                        if (subSys == nullptr)continue;
                        subSys->enable(isShow);
                    }
                }
                else {
                    for (int i : idList) {
                        Acoustics::FITKAbstractFESubSys* subSys = _FEModel->getFESubSysManager()->getDataByID(i);
                        if (subSys == nullptr)continue;
                        subSys->enable(isShow);
                    }
                }
            }
            //判断FE面
            if (_FEModel && _FEModel->getFEFaceManager()) {
                if (idList.isEmpty()) {
                    for (int i = 0; i < _FEModel->getFEFaceManager()->getDataCount(); i++) {
                        Acoustics::FITKAcousticsFEFace* feFace = _FEModel->getFEFaceManager()->getDataByIndex(i);
                        if (feFace == nullptr)continue;
                        feFace->enable(isShow);
                    }
                }
                else {
                    for (int i : idList) {
                        Acoustics::FITKAcousticsFEFace* feFace = _FEModel->getFEFaceManager()->getDataByID(i);
                        if (feFace == nullptr)continue;
                        feFace->enable(isShow);
                    }
                }
            }
            //判断传感器
            if (_FEModel && _FEModel->getSensorManager()) {
                if (idList.isEmpty()) {
                    for (int i = 0; i < _FEModel->getSensorManager()->getDataCount(); i++) {
                        Acoustics::FITKAcousticsSensors* sensor = _FEModel->getSensorManager()->getDataByIndex(i);
                        if (sensor == nullptr)continue;
                        sensor->enable(isShow);
                    }
                }
                else {
                    for (int i : idList) {
                        Acoustics::FITKAcousticsSensors* sensor = _FEModel->getSensorManager()->getDataByID(i);
                        if (sensor == nullptr)continue;
                        sensor->enable(isShow);
                    }
                }
            }
            //更新模型树界面item状态（该函数的调用需在刷新渲染之前）
            updateModelTreeWidgetItem();
            //刷新渲染层
            operGraph->updateSEASubSystems();
            operGraph->updateFESubSystems();
            operGraph->updateFEFaces();
            operGraph->updateSensors();
            break;
        }
        case GUI::GUIDialogPickType::Load: {
            if (_physics && _physics->getFITKAcousticsLoadManager()) {
                if (idList.isEmpty()) {
                    for (int i = 0; i < _physics->getFITKAcousticsLoadManager()->getDataCount(); i++) {
                        Acoustics::FITKAcousticsAbstractLoad* load = _physics->getFITKAcousticsLoadManager()->getDataByIndex(i);
                        if (load == nullptr)continue;
                        load->enable(isShow);
                    }
                }
                else {
                    for (int i : idList) {
                        Acoustics::FITKAcousticsAbstractLoad* load = _physics->getFITKAcousticsLoadManager()->getDataByID(i);
                        if (load == nullptr)continue;
                        load->enable(isShow);
                    }
                }
            }
            //更新模型树界面item状态（该函数的调用需在刷新渲染之前）
            updateModelTreeWidgetItem();
            //刷新渲染层
            operGraph->updateLoads();
            break;
        }
        case GUI::GUIDialogPickType::Junction: {
            if (_DiscModel && _DiscModel->getJunctionManager()) {
                if (idList.isEmpty()) {
                for (int i = 0; i < _DiscModel->getJunctionManager()->getDataCount(); i++) {
                    Acoustics::FITKAbstractJunction* junction = _DiscModel->getJunctionManager()->getDataByIndex(i);
                    if (junction == nullptr)continue;
                    junction->enable(isShow);
                }
            }
            else {
                for (int i : idList) {
                    Acoustics::FITKAbstractJunction* junction = _DiscModel->getJunctionManager()->getDataByID(i);
                    if (junction == nullptr)continue;
                    junction->enable(isShow);
                }
            }
            }
            //更新模型树界面item状态（该函数的调用需在刷新渲染之前）
            updateModelTreeWidgetItem();
            //刷新渲染层
            operGraph->updateJunctions();
            break;
        }
        }
    }

    void GUIVisibilityDialog::updateModelTreeWidgetItem()
    {
        //获取渲染器
        Oper::TreeEventOperator* oper = FITKOPERREPO->getOperatorT<Oper::TreeEventOperator>("OperModelTreeEvent");
        if (oper == nullptr)return;
        oper->updateModelTreeItemState();
    }

    QList<Interface::FITKAbsVirtualTopo*> GUIVisibilityDialog::getAllGeometryVirTopos()
    {
        QList<Interface::FITKAbsVirtualTopo*> virTopoList = {};
        Acoustics::FITKAcousticsGeometryData* geometryData = FITKAPP->getGlobalData()->getGeometryData<Acoustics::FITKAcousticsGeometryData>();
        if (geometryData == nullptr) {
            return virTopoList;
        }

        //获取所有的集合命令
        QList<Interface::FITKAbsGeoCommand*> allGeo = {};
        const int n = geometryData->getDataCount();
        for (int i = 0; i < n; ++i) {
            Interface::FITKAbsGeoCommand* geo = geometryData->getDataByIndex(i);
            if (geo == nullptr) {
                continue;
            }
            allGeo.append(geo);
        }

        //获取所有点、线、面的虚拓扑
        for (Interface::FITKAbsGeoCommand* geoCom : allGeo) {
            if (geoCom == nullptr) {
                continue;
            }
            Interface::FITKShapeVirtualTopoManager* virTopoPointManager = geoCom->getShapeVirtualTopoManager(Interface::FITKGeoEnum::VTopoShapeType::VSPoint);
            if (virTopoPointManager != nullptr) {
                for (int i = 0; i < virTopoPointManager->getDataCount(); i++) {
                    virTopoList.append(virTopoPointManager->getDataByIndex(i));
                }
            }
            Interface::FITKShapeVirtualTopoManager* virTopoEdgeManager = geoCom->getShapeVirtualTopoManager(Interface::FITKGeoEnum::VTopoShapeType::VSEdge);
            if (virTopoEdgeManager != nullptr) {
                for (int i = 0; i < virTopoEdgeManager->getDataCount(); i++) {
                    virTopoList.append(virTopoEdgeManager->getDataByIndex(i));
                }
            }
            Interface::FITKShapeVirtualTopoManager* virTopoFaceManager = geoCom->getShapeVirtualTopoManager(Interface::FITKGeoEnum::VTopoShapeType::VSFace);
            if (virTopoFaceManager != nullptr) {
                for (int i = 0; i < virTopoFaceManager->getDataCount(); i++) {
                    virTopoList.append(virTopoFaceManager->getDataByIndex(i));
                }
            }
        }
        return virTopoList;
    }

    void GUIVisibilityDialog::checkGeoEdgeIsShow()
    {
        Acoustics::FITKAcousticsGeometryData* geometryData = FITKAPP->getGlobalData()->getGeometryData<Acoustics::FITKAcousticsGeometryData>();
        if (geometryData == nullptr) {
            return;
        }

        //获取所有的线虚拓扑
        QList<Interface::FITKAbsVirtualTopo*> edgeVirTopoList = {};
        const int n = geometryData->getDataCount();
        for (int i = 0; i < n; i++) {
            Interface::FITKAbsGeoCommand* geo = geometryData->getDataByIndex(i);
            if (geo == nullptr) {
                continue;
            }
            Interface::FITKShapeVirtualTopoManager* virTopoEdgeManager = geo->getShapeVirtualTopoManager(Interface::FITKGeoEnum::VTopoShapeType::VSEdge);
            if (virTopoEdgeManager == nullptr) {
                continue;
            }

            for (int j = 0; j < virTopoEdgeManager->getDataCount(); j++) {
                Interface::FITKAbsVirtualTopo* virTopo = virTopoEdgeManager->getDataByIndex(j);
                if (virTopo == nullptr) {
                    continue;
                }
                edgeVirTopoList.append(virTopo);
            }
        }

        //处理线是否隐藏
        for (Interface::FITKAbsVirtualTopo* edgeVirTopo : edgeVirTopoList) {
            if (edgeVirTopo == nullptr) {
                continue;
            }

            //通过拓扑关系查询器查询线所关联的面
            Interface::FITKVirtualTopoMapper topoMapper;
            topoMapper.mapTopo(edgeVirTopo, Interface::FITKGeoEnum::VTopoShapeType::VSFace);

            //判断所关联的面是否全部隐藏
            bool isAllFaceHide = true;
            if (topoMapper.length() < 1) {
                isAllFaceHide = false;
            }
            else {
                for (int j = 0; j < topoMapper.length(); j++) {
                    Interface::FITKAbsVirtualTopo* vTopoFace = topoMapper.virtualTopo(j);
                    if (vTopoFace == nullptr) {
                        continue;
                    }

                    if (vTopoFace->isEnable() == true) {
                        isAllFaceHide = false;
                        break;
                    }
                }
            }

            //如果所关联的全部面都被隐藏，隐藏该线
            if (isAllFaceHide == true) {
                edgeVirTopo->enable(false);
            }
        }
    }

    void GUIVisibilityDialog::checkGeoPointIsShow()
    {
        Acoustics::FITKAcousticsGeometryData* geometryData = FITKAPP->getGlobalData()->getGeometryData<Acoustics::FITKAcousticsGeometryData>();
        if (geometryData == nullptr) {
            return;
        }

        //获取所有的点虚拓扑
        QList<Interface::FITKAbsVirtualTopo*> pointVirTopoList = {};
        const int n = geometryData->getDataCount();
        for (int i = 0; i < n; i++) {
            Interface::FITKAbsGeoCommand* geo = geometryData->getDataByIndex(i);
            if (geo == nullptr) {
                continue;
            }
            Interface::FITKShapeVirtualTopoManager* virTopoPointManager = geo->getShapeVirtualTopoManager(Interface::FITKGeoEnum::VTopoShapeType::VSPoint);
            if (virTopoPointManager == nullptr) {
                continue;
            }

            for (int j = 0; j < virTopoPointManager->getDataCount(); j++) {
                Interface::FITKAbsVirtualTopo* virTopo = virTopoPointManager->getDataByIndex(j);
                if (virTopo == nullptr) {
                    continue;
                }
                pointVirTopoList.append(virTopo);
            }
        }

        //处理点是否隐藏
        for (Interface::FITKAbsVirtualTopo* pointVirTopo : pointVirTopoList) {
            if (pointVirTopo == nullptr) {
                continue;
            }

            //通过拓扑关系查询器查询点所关联的线
            Interface::FITKVirtualTopoMapper topoMapper;
            topoMapper.mapTopo(pointVirTopo, Interface::FITKGeoEnum::VTopoShapeType::VSEdge);

            //判断所关联的线是否全部隐藏
            bool isAllEdgeHide = true;
            if (topoMapper.length() < 1) {
                isAllEdgeHide = false;
            }
            else {
                for (int j = 0; j < topoMapper.length(); j++) {
                    Interface::FITKAbsVirtualTopo* vTopoFace = topoMapper.virtualTopo(j);
                    if (vTopoFace == nullptr) {
                        continue;
                    }

                    if (vTopoFace->isEnable() == true) {
                        isAllEdgeHide = false;
                        break;
                    }
                }
            }

            //如果所关联的全部线都被隐藏，隐藏该点
            if (isAllEdgeHide == true) {
                pointVirTopo->enable(false);
            }
        }
    }
}

